﻿using Basic.ScheduledTask.Abstract;
using Hangfire;
using Microsoft.Extensions.Options;
using System.Linq.Expressions;

namespace Basic.ScheduledTask.HangfireImplement;

/// <summary>
/// 基于Hangfire的定时任务管理
/// </summary>
public class HangfireJobManager : IJobManager
{
    private RecurringJobOptions JobOptions;
    public HashSet<string> LoadedJobIds { get; }

    public HangfireJobManager(IOptions<JobDbConfig> options)
    {
        LoadedJobIds = new HashSet<string>();
        JobOptions = new RecurringJobOptions
        {
            TimeZone = TimeZoneInfo.Local,
            MisfireHandling = MisfireHandlingMode.Relaxed,
        };
    }

    #region 异步

    public void AddOnceJob(Expression<Func<Task>> expression) => BackgroundJob.Enqueue(expression);

    public void AddOnceJob(Expression<Func<Task>> expression, DateTimeOffset time) => BackgroundJob.Schedule(expression, time);

    public bool AddRecurringJob(string jobId, Expression<Func<Task>> expression, string cron)
    {
        RecurringJob.AddOrUpdate(jobId, expression, cron, JobOptions);
        LoadedJobIds.Add(jobId);
        return true;
    }

    public bool AddRecurringJob<T>(string jobId, Func<T, Task> func, string cron) where T : class
    {
        RecurringJob.AddOrUpdate<T>(jobId, p => func.Invoke(p), cron, JobOptions);
        LoadedJobIds.Add(jobId);
        return true;
    }

    public void DelayJob(Expression<Func<Task>> expression, TimeSpan delayTime) => BackgroundJob.Schedule(expression, delayTime);

    #endregion

    public void AddOnceJob(IScheduledJob job)
    {
        BackgroundJob.Enqueue(() => job.ExecuteAsync());
    }

    public void AddOnceJob(IScheduledJob job, TimeSpan delayTime)
    {
        BackgroundJob.Schedule(() => job.ExecuteAsync(), delayTime);
    }

    public void AddOnceJob(IScheduledJob job, DateTimeOffset time)
    {
        BackgroundJob.Schedule(() => job.ExecuteAsync(), time);
    }

    public bool AddRecurringJob(string jobId, IScheduledJob job, object[] paras = null)
    {
        if (string.IsNullOrEmpty(job.Cron))
            return false;
        RecurringJob.AddOrUpdate(jobId, () => job.ExecuteAsync(), job.Cron, JobOptions);
        LoadedJobIds.Add(jobId);
        return true;
    }

    public void RemoveJob(string jobId)
    {
        RecurringJob.RemoveIfExists(jobId);
        LoadedJobIds.Remove(jobId);
    }

    public bool Contains(string jobId) => LoadedJobIds.Contains(jobId);

}